- 每个进程一次最多可以有9个文件描述符
重定向错误:STDERR文件描述符被设为2,可以选择只重定向错误消息,将该文件描述符放在重定向符号前,该值必须紧紧地放在重定向符号前,否则不会工作:
1ls -al badfile 2> test412$cat test4ls: cannot access badfile: No such file or directory如果想重定向错误和正常输出,必须用两个重定向符号,需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件:
1ls -al test test2 test3 badtest 2> test6 1> test7也可以将STDERR和STDOUT的输出重定向到同一个输出文件中,可以使用特殊的重定向符号
&>
1ls -al test test2 test3 badtest &> test7如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR,你需要做的就是使用输出重定向符来将输出消息重定向到STDERR文件描述符,在重定向到文件描述符时,必须在文件描述符数字之前加一个
&
:1echo "This is an error message" >&2这样会在脚本的STDERR文件描述符所指向的位置显示文本,而不是通常的STDOUT:
123#!/bin/bashecho "This is an error" >&2echo "This is normal output"123$ ./test.shThis is an errorThis is normal output默认情况下,Linux会将STDERR导向STDOUT,但是如果你在运行脚本时重定向了STDERR,脚本中所有导向STDERR的文本都会被重定向:
1$ ./test.sh 2> test9此时错误信息就会被重定向到test9文件中,而正常信息还是会显示在显示器上
如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很繁琐,你可以用exec命令告诉shell脚本执行期间重定向某个特定文件描述符:
1234#!/bin/bashexec 1>testoutecho "This is a test of redirecting all output"echo "from a script to another file"1$./test.shexec命令会启动一个新的shell并将STDOUT文件描述符重定向到文件,脚本中发给STDOUT的所有输出会被重定向到文件
- 1234567#!/bin/bashexec 2>testerrorecho "This is the start of the script"echo "now redirecting all output to another location"exec 1>testoutecho "This output should go to the testout file"echo "but this should go to the testerror file" >&21234567$ ./test.shThis is the start of the scriptnow redirecting all output to another location$ cat testoutThis output should go to the testout file$ cat testerrorbut this should go to the testerror file
可以将STDIN从键盘重定向到其他位置,exec命令允许你将STDIN重定向到Linux系统上的文件中:
1exec 0< testfile这个命令会告诉shell从文件中获取输入而不是STDIN:
12345678#!/bin/bashecho 0< testfilecount=1while read linedoecho "Line #count: line"count=[ count + 1 ]done1$ ./test.sh一个进程最多可以使用9个文件描述符,除了0、1、2外另外6个都可以在shell脚本中使用,用作输入和输出重定向:
12345#!/bin/bashexec 3>testoutecho "This should display on the monitor"echo "and this should be stored in the file" >&3echo "Then this should be back on the monitor"12345$ ./testThis should display on the monitorThen this should be back on the monitor$ cat testoutand this should be stored in the file恢复重定向的文件描述符:
1234567#!/bin/bashexec 3>&1exec 1>testoutecho "This should store in the output file"echo "along with this line"echo 1>&3echo "Now things should be back to normal"12345$ ./test.shNow things should be back to normal$ cat testoutThis should store in the output filealong with this line上面这段代码中首先将文件描述符3重定向到文件描述符1的当前位置,也就是STDOUT,这意味着任何发送给文件描述符3的输出都将显示在显示器上。
第二个exec命令将STDOUT重定向到文件,shell现在将发送给STDOUT的输出直接重定向到输出文件中,但是文件描述符3仍然会指向STDOUT原来的位置,也就是显示器,如果此时将输出数据发送到文件描述符3,它仍然会显示在显示器上,尽管STDOUT已经被重定向了。
在向STDOUT(现在指向一个文件)发送一些输出后,脚本将STDOUT重定向到文件描述符3的当前位置(现在仍然是显示器),这意味着现在STDOUT又指向了它原来的位置:显示器。
创建读写文件描述符,可以用一个文件描述符对同一个文件进行读写,对同一个文件进行读写,shell会维护一个内部指针, 指明在文件中的当前位置,任何读写都会从文件指针上次的位置开始:
12345#!/bin/bashexec 3<>testfileread line <&3echo "Read: $line"echo "This is a test line" >&312345678910$ cat testfileThis is the first line.This is the second line.This is the third line.$ ./test.shcat testfileThis is the first line.This is a test lineine.This is the third line.当脚本向文件中写入数据时,它会从文件指针所处的位置开始,read命令读取了第一行数据,所以它使得文件指针指向了第二行数据的第一个字符,在echo语句将数据输出到文件时,它会将数据放到文件指针的当前位置,覆盖了该位置的已有数据。
关闭文件描述符:要关闭文件描述符,将它重定向到特殊符号
&-
:1exec 3>&-列出打开的文件描述符:
lsof命令会列出整个Linux系统打开的所有文件描述符,lsof命令位于
/usr/sbin
命令,要想以普通用户账户来运行它,必须通过全路径来引用:/usr/sbin/lsof
。lsof有几个常用的命令行选项,
-p
选项允许指定进程ID(PID),-d
选项允许指定要显示的文件描述符编号,要想知道进程的当前PID,可以用特殊环境变量$$
(shell会将它设为当前PID),-a
选项用来对其他两个选项的结果进行AND运算
阻止命令输出:
通过将STDERR重定向到null文件中将全部消息删除,shell输出到null文件的任何数据都不会保存,更不会显示:
12ls -al > /dev/nullls -al badfile test16 2> /dev/null也可以在输入重定向中将
/dev/null
作为输入文件,由于/dev/null
中不含有任何内容,因此通常可以用它来快速清除现有文件中的数据,而不用先删除文件再重新创建,这是清除日志文件的一个常用方法。
- 大多数Linux发行版配置了在启动时自动删除/tmp目录的所有文件,mktemp命令可以在/tmp目录中创建一个唯一的临时文件,shell会创建这个文件,但不用默认的umask值,它会将文件的读和写权限分配给文件的属主,并将你设为文件的属主,一旦创建了文件,你就在脚本中有了完整的读写权限,但其他人无法访问(root用户除外)
默认情况下,mktemp命令会在本地目录中创建一个文件,要用mktemp命令在本地目录中创建一个临时文件,你只要指定一个文件名模板就醒了,模板可以包含任意文本文件名,在文件名末尾加上6个X就行了:
1$ mktemp testing.XXXXXXmktmp命令会用6个字符码替换这6个X,从而保证文件名在目录中是唯一的,你可以创建多个临时文件,他可以保证每个文件是唯一的:
1234567891011#!/bin/bashtempfile=$(mktemp test.XXXXXX)exec 3>$tempecho "This script writes to temp file $tempfile"echo "This is the first line" >&3echo "This is the second line" >&3echo "This is the last line" >&3exec 3>&-echo "Done creating temp file. The contents are:"cat $tempfilerm -f $tempfile 2> /dev/null123456$ ./testThis script writes to temp file test19.vCHoyaDone creating temp file. The contents are:This is the first lineThis is the second line.This is the last line.-t选项会强制mktemp命令在系统的临时目录创建该文件,此时mktemp命令会返回用来创建临时文件的全路径,而不是只有文件名
-d选项会使得mktemp命令来创建一个临时目录而不是临时文件:
12345678910#!/bin/bashtempdir=$(mktemp -d dir.XXXXXX)cd $tempdirtempfile1=$(mktemp temp.XXXXXX)tempfile2=$(mktemp temp.XXXXXX)exec 7> $tempfile1exec 8> $tempfile2echo "Sending data to directory $tempdir"echo "This is a test line of data for $tempfile1" >&7echo "This is a test line of data for $tempfile2" >&8tee命令相当于管道的一个T型接头,它将从STDIN过来的数据同时发往两处,一处是STDOUT,另一处是tee命令行所指定的文件名:
1tee filename1$ date | tee testfile默认情况下,tee命令会在每次使用时覆盖输出文件内容,如果想将数据追加到文件中,必须使用-a选项:
1$ date | tee -a testfile举例:读取csv格式的数据文件,输出SQL INSERT语句来将数据插入数据库:
12345678910#!/bin/bashoutfile=members.sqlIFS=,while read lname fname address city state zipdocat >> $outfile << EOFINSERT INTO members (lname, fname, address, city, state, zip) VALUES('lname', 'fname', 'address', 'city', 'state', 'zip');EOFdone < ${1}脚本中使用了3处重定向,while循环使用read语句来从数据文件中读取文本,这是通过在done语句中出现的重定向符号来实现的,命令行的第一个参数即members.csv文件会作为待读取数据的文件。脚本中另外两处重定向操作出现在同一条语句中:
1cat >> $outfile << EOF这条语句中包含一个输出追加重定向和一个输入追加重定向,输出重定向将cat命令的输出追加到
$outfile
变量指定的文件中,cat命令的输入不再取自标准输入,而是被重定向到脚本中存储的数据,EOF符号标记了追加到文件中的数据的起止(内联输入重定向)。